package endpoint

import (
	"center/db"
	"center/db/models"
	"common/pb"
	"common/rs"
	"common/uuid"
	"context"
	"errors"
	"github.com/wuzfei/go-helper/maps"
	"go.uber.org/zap"
)

func (s *MetainfoServer) DownloadObject(ctx context.Context, req *pb.ObjectDownloadRequest) (_ *pb.ObjectDownloadResponse, err error) {
	var streamId uuid.UUID
	defer func() {
		err = Error.Wrap(err)
		s.log.Info("DownloadObject",
			zap.String("streamId", streamId.String()),
			zap.ByteString("bucket", req.Bucket), zap.ByteString("encryptedObjectKey", req.EncryptedObjectKey), zap.Error(err))
	}()
	//检查参数
	apiKey, err := s.validateAuth(ctx, req.Header)
	if err != nil {
		return nil, err
	}
	//检查bucket是否存在
	s.log.Info("GetBucketByName", zap.String("bucket", string(req.Bucket)),
		zap.String("own", apiKey.Head().String()))
	//bucket, err := s.db.GetBucketByName(ctx, string(req.Bucket), apiKey.Head())
	//if err != nil {
	//	return nil, err
	//}

	//查找对象
	obj, err := s.db.GetObject(ctx, db.ObjectOne{EncryptObjectKey: req.EncryptedObjectKey})
	if err != nil {
		s.log.Info("GetObject ", zap.Error(err))
		return nil, err
	}
	if obj.Status != models.ObjectStatusCommitted {
		err = errors.New("该文件已损坏无法下载")
		return nil, err
	}
	streamId = obj.StreamId

	response := &pb.ObjectDownloadResponse{
		StreamId:           obj.StreamId.Bytes(),
		Rs:                 rs.ToPbRs(obj.Redundancy),
		Segments:           make([]*pb.SegmentDownload, 0),
		EncryptedObjectKey: []byte(obj.EncryptObjectKey),
		EncryptedKey:       obj.EncryptedKey,
		Inline:             obj.Inline,
		PlainSize:          obj.PlainSize,
		SegmentCount:       int32(obj.SegmentCount),
		SegmentSize:        int32(obj.SegmentSize),
		Attributes:         obj.Attribute,
	}
	if obj.Inline {
		response.Data, err = s.db.GetInlineByStreamId(ctx, obj.StreamId.Bytes())
		return response, err
	}

	if req.Limit == 0 {
		for i := 0; i < obj.SegmentCount; i++ {
			if seg, err := s.getDownloadSegmentInfo(ctx, obj.StreamId, i); err != nil {
				return nil, err
			} else {
				response.Segments = append(response.Segments, seg)
			}
		}
	} else {
		//获取指定的某个segment信息
		if seg, err := s.getDownloadSegmentInfo(ctx, obj.StreamId, int(req.Limit-1)); err != nil {
			return nil, err
		} else {
			response.Segments = append(response.Segments, seg)
		}
	}
	return response, err
}

func (s *MetainfoServer) getDownloadSegmentInfo(ctx context.Context, streamId uuid.UUID, segmentIdx int) (*pb.SegmentDownload, error) {
	segmentsOfDatabase, err := s.db.GetSegmentByStreamIdAndPosition(ctx, streamId, segmentIdx)
	if err != nil {
		return nil, err
	}
	nodeIdxs := maps.Values(segmentsOfDatabase.NodePieces)
	nodes, err := s.db.GetNodesByIdxs(ctx, nodeIdxs)
	if err != nil {
		return nil, err
	}
	nodeMap := make(map[uint32]*models.Node, 0)
	for _, v := range nodes {
		nodeMap[v.IDx] = v
	}
	nodePieces := make([]*pb.NodePieces, 0)

	//获取节点信息
	for idx, _nodeIdx := range segmentsOfDatabase.NodePieces {
		_nodeInfo, ok := nodeMap[_nodeIdx]
		if !ok {
			continue
		}
		nodePieces = append(nodePieces, &pb.NodePieces{
			Index: int32(idx),
			NodeInfo: &pb.NodeInfo{
				NodeId:  _nodeInfo.ID.Bytes(),
				PeerFwd: int32(_nodeInfo.Fwd),
				StorageNodeAddress: &pb.NodeAddress{
					Ip:       _nodeInfo.Ip,
					Ipv6:     _nodeInfo.Ipv6,
					DeviceId: _nodeInfo.DevId,
					Port:     int32(_nodeInfo.Port),
					Nat:      int32(_nodeInfo.Nat),
				},
			},
		})
	}
	segmentDownload := pb.SegmentDownload{
		Index:       int32(segmentIdx),
		Pieces:      nodePieces,
		Padding:     int32(segmentsOfDatabase.Pad),
		SegmentSize: segmentsOfDatabase.PlainSize,
	}

	if len(segmentsOfDatabase.NodePieces) == 0 {
		return nil, errors.New("节点数量为空")
	}
	return &segmentDownload, nil
}
